package me.flyray.bsin.server.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import me.flyray.bsin.blockchain.config.S11eProtocolProperties;
import me.flyray.bsin.blockchain.connection.BsinBlockChainEngineFactory;
import me.flyray.bsin.blockchain.protocol.S11eProtocolService;
import me.flyray.bsin.context.BsinServiceContext;
import me.flyray.bsin.domain.entity.*;
import me.flyray.bsin.domain.enums.AssetsCollectionType;
import me.flyray.bsin.domain.enums.DidProfileType;
import me.flyray.bsin.exception.BusinessException;
import me.flyray.bsin.facade.engine.DidProfileServiceEngine;
import me.flyray.bsin.facade.engine.PassCardServiceEngine;
import me.flyray.bsin.facade.engine.WalletServiceEngine;
import me.flyray.bsin.facade.response.DigitalAssetsDetailRes;
import me.flyray.bsin.facade.response.DigitalAssetsItemRes;
import me.flyray.bsin.facade.response.PassCardVo;
import me.flyray.bsin.facade.service.*;
import me.flyray.bsin.infrastructure.biz.DigitalAssetsItemBiz;
import me.flyray.bsin.infrastructure.mapper.*;
import me.flyray.bsin.mybatis.utils.Pagination;
import me.flyray.bsin.security.contex.LoginInfoContextHelper;
import me.flyray.bsin.security.domain.LoginUser;
import me.flyray.bsin.utils.BsinSnowflake;
import me.flyray.bsin.utils.StringUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.shenyu.client.apache.dubbo.annotation.ShenyuDubboService;
import org.apache.shenyu.client.apidocs.annotations.ApiDoc;
import org.apache.shenyu.client.apidocs.annotations.ApiModule;
import org.apache.shenyu.client.dubbo.common.annotation.ShenyuDubboClient;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author bolei
 * @date 2023/6/28 16:37
 * @desc
 */

@Slf4j
@ShenyuDubboService(path = "/passCard", timeout = 60000)
@ApiModule(value = "passCard")
public class PassCardServiceImpl implements PassCardServiceEngine {

  @Autowired public CustomerPassCardMapper customerPassCardMapper;

  @Autowired private DigitalAssetsCollectionMapper digitalAssetsCollectionMapper;
  @Autowired private DigitalAssetsItemMapper digitalAssetsItemMapper;

  @Autowired private DigitalAssetsItemBiz digitalAssetsItemBiz;

//  @DubboReference(version = "${dubbo.provider.version}")
//  private CustomerService customerService;
//
//  @DubboReference(version = "${dubbo.provider.version}")
//  private MerchantService merchantService;

  @DubboReference(version = "${dubbo.provider.version}")
  private MemberService memberService;

  @Autowired
  private WalletServiceEngine walletService;

  @DubboReference(version = "${dubbo.provider.version}")
  private DigitalAssetsCollectionService digitalAssetsCollectionService;

  @DubboReference(version = "${dubbo.provider.version}")
  private DigitalAssetsItemService digitalAssetsItemService;

  @DubboReference(version = "${dubbo.provider.version}")
  private CustomerProfileService customerProfileService;

  @Autowired
  DidProfileServiceEngine didProfileServiceEngine;

  @Autowired
  private S11eProtocolService s11eProtocolService;

  @Autowired
  private WalletMapper walletMapper;
  @Autowired
  private WalletAccountMapper walletAccountMapper;
  @Autowired
  private ChainCoinMapper chainCoinMapper;
  @Autowired
  private BsinBlockChainEngineFactory bsinBlockChainEngineFactory;
  @Autowired
  private DidProfileMapper didProfileMapper;
  @Autowired
  private S11eProtocolProperties s11eConfig;

  /**
   * 统一走 DigitalAssetsCollectionService 的 issue
    */
  @ShenyuDubboClient("/issue")
  @ApiDoc(desc = "issue")
  @Override
  public DigitalAssetsCollection issue(Map<String, Object> requestMap) throws Exception {
    LoginUser loginUser = LoginInfoContextHelper.getLoginUser();

    String merchantNo = StringUtils.defaultIfBlank(loginUser.getMerchantNo(), loginUser.getTenantMerchantNo());

    Boolean onChainFlag = MapUtils.getBoolean(requestMap, "onChainFlag");
    // TODO 写入卡资产相关信息
    DigitalAssetsCollection digitalAssetsColletion = new DigitalAssetsCollection();

    if(onChainFlag){
      // 找到链上品牌
      DidProfile didProfile = didProfileMapper.selectOne(new LambdaQueryWrapper<DidProfile>().eq(DidProfile::getBizRoleTypeNo, merchantNo));

      // 查询品牌的钱包账户，初始化钱包账户
      // 根据 MapUtils.getString(requestMap, "chainIdentifier") 获取链本币
      String chainIdentifier = didProfile.getChainIdentifier();
      String nativeCoin = bsinBlockChainEngineFactory.getChainNativeCoin(chainIdentifier);
      log.info("准备用链上资料，链标识:{}，链本币:{}", chainIdentifier, nativeCoin);
      // 根据 chainIdentifier 查询币种
      ChainCoin chainNativeCoin = chainCoinMapper.selectOne(new LambdaQueryWrapper<ChainCoin>()
              .eq(ChainCoin::getChainIdentifier, chainIdentifier)
              .eq(ChainCoin::getCoin, nativeCoin));
      log.debug("链本币查询结果: {}", chainNativeCoin);

      // 查询商户钱包
      LambdaQueryWrapper<Wallet> walletQueryWrapper = new LambdaQueryWrapper<>();
      walletQueryWrapper.eq(Wallet::getBizRoleTypeNo, merchantNo);
      Wallet wallet = walletMapper.selectOne(walletQueryWrapper);
      log.debug("查询商户:{} 对应钱包: {}", merchantNo, wallet);

      LambdaQueryWrapper<WalletAccount> queryWrapper = new LambdaQueryWrapper<>();
      queryWrapper.eq(WalletAccount::getWalletNo, wallet.getSerialNo());
      queryWrapper.eq(WalletAccount::getChainCoinNo, chainNativeCoin.getSerialNo());
      WalletAccount walletAccount = walletAccountMapper.selectOne(queryWrapper);
      log.debug("链本币账户: {}", walletAccount);
      
      if (walletAccount == null) {
        throw new BusinessException("WAAS_WALLET_ACCOUNT_MISSING", 
            "商户钱包账户不存在，无法发行PassCard");
      }

      // 获取Profile合约地址
      String profileAddress = didProfile.getContractAddress();
      if (StringUtils.isBlank(profileAddress)) {
        throw new BusinessException("WAAS_PROFILE_ADDRESS_MISSING", 
            "品牌Profile合约地址为空，无法发行PassCard");
      }

      // 获取PassCard Issuer地址（这是合约地址，不是钱包地址）
      // 优先通过 getProfileIssuer 查询链上数据（支持品牌专属 Issuer）
      // 如果查询失败，使用配置中的平台默认 Issuer 作为后备
      String chainEnv = MapUtils.getString(requestMap, "chainEnv", "test");
      String issuerAddress = null;
      
      try {
        Map<String, Object> issuerRequest = new HashMap<>();
        issuerRequest.put("chainIdentifier", chainIdentifier);
        issuerRequest.put("chainEnv", chainEnv);
        issuerRequest.put("assetFactoryAddress", s11eConfig.getContracts().getAssetFactory());
        issuerRequest.put("profileAddress", profileAddress);  // 使用品牌的 Profile 地址查询
        issuerRequest.put("assetType", "1");  // PassCard = 1
        
        log.info("查询PassCard Issuer: profileAddress={}", profileAddress);
        Map<String, Object> issuerResult = s11eProtocolService.getProfileIssuer(issuerRequest);
        issuerAddress = (String) issuerResult.get("issuer");
        if (StringUtils.isBlank(issuerAddress)) {
          issuerAddress = (String) issuerResult.get("issuerAddress");
        }
        
        // 检查是否为零地址（表示未找到 Issuer）
        if (StringUtils.isNotBlank(issuerAddress) && !isZeroAddress(issuerAddress)) {
          log.info("从链上查询到PassCard Issuer合约地址: {} (可能是品牌专属Issuer或平台默认Issuer)", issuerAddress);
        } else {
          log.warn("链上查询返回零地址，表示未找到Issuer，将使用配置中的默认Issuer");
          issuerAddress = null;  // 重置为零，以便后续使用配置
        }
      } catch (Exception e) {
        log.warn("链上查询PassCard Issuer失败，将使用配置中的默认Issuer: {}", e.getMessage());
        issuerAddress = null;  // 确保使用配置
      }
      
      // 构建issuePassCard请求参数
      Map<String, Object> issueRequest = new HashMap<>();
      issueRequest.put("chainIdentifier", chainIdentifier);
      issueRequest.put("chainEnv", chainEnv);
      issueRequest.put("privateKey", walletAccount.getPrivateKey());
      
      // PassCard参数（从requestMap获取，如果没有则使用默认值）
      issueRequest.put("name", MapUtils.getString(requestMap, "name"));
      issueRequest.put("symbol", MapUtils.getString(requestMap, "symbol"));
      issueRequest.put("baseURI", MapUtils.getString(requestMap, "baseURI", 
          s11eConfig.getBaseUri() + "passcard/"));
      // maxSupply 必须有值，如果未提供则使用默认值 10000
      String maxSupply = MapUtils.getString(requestMap, "maxSupply");
      if (StringUtils.isBlank(maxSupply)) {
        maxSupply = "10000";  // 默认最大供应量
        log.warn("maxSupply为空，使用默认值: {}", maxSupply);
      }
      issueRequest.put("maxSupply", maxSupply);
      issueRequest.put("erc6551Registry", s11eConfig.getContracts().getErc6551Registry());
      // assetOwner 应该是 Profile 地址，因为 PassCard 是品牌的资产，应该属于 Profile 合约
      issueRequest.put("assetOwner", profileAddress);
      
      // ✅ 优先尝试直接调用 PassCardIssuer（如果查询到了品牌专属 Issuer）
      // 适用于：品牌专属 Issuer，品牌是 owner，可以直接调用（更高效）
      if (StringUtils.isNotBlank(issuerAddress) && !isZeroAddress(issuerAddress)) {
        issueRequest.put("issuerAddress", issuerAddress);
        log.info("准备直接通过PassCardIssuer发行PassCard: name={}, symbol={}, maxSupply={}, issuerAddress={}, profileAddress={}, assetOwner={}", 
            issueRequest.get("name"), issueRequest.get("symbol"), 
            issueRequest.get("maxSupply"), issuerAddress, profileAddress, profileAddress);
      } else {
        // ✅ 通过 AssetFactory 调用（适用于平台默认 Issuer）
        String assetFactoryAddress = s11eConfig.getContracts().getAssetFactory();
        if (StringUtils.isBlank(assetFactoryAddress)) {
          throw new BusinessException("WAAS_ASSET_FACTORY_ADDRESS_MISSING", 
              "AssetFactory 地址未配置，请在配置文件中设置 asset-factory");
        }
        issueRequest.put("assetFactoryAddress", assetFactoryAddress);
        issueRequest.put("profileAddress", profileAddress);  // AssetFactory 需要 profileAddress
        log.info("准备通过AssetFactory发行PassCard: name={}, symbol={}, maxSupply={}, assetFactoryAddress={}, profileAddress={}, assetOwner={}", 
            issueRequest.get("name"), issueRequest.get("symbol"), 
            issueRequest.get("maxSupply"), assetFactoryAddress, profileAddress, profileAddress);
      }

      // 发行会员卡
      Map<String, Object> chainResult = s11eProtocolService.issuePassCard(issueRequest);


      // 处理返回结果
      // SDK 会自动从交易回执中解析 PassCard 地址，并总是设置 success=true
      if (chainResult != null) {
        String passCardAddress = (String) chainResult.get("passCardAddress");
        String txHash = (String) chainResult.get("txHash");
        String transactionHash = (String) chainResult.get("transactionHash");
        Boolean success = (Boolean) chainResult.get("success");
        
        // SDK 总是设置 success=true，主要关注 passCardAddress 是否存在
        if (passCardAddress != null && !passCardAddress.isEmpty()) {
          // 将PassCard地址保存到requestMap，供后续使用
          requestMap.put("passCardAddress", passCardAddress);
          requestMap.put("chainTxHash", txHash != null ? txHash : transactionHash);
          log.info("链上PassCard发行成功: passCardAddress={}, txHash={}", 
              passCardAddress, txHash != null ? txHash : transactionHash);
        } else {
          // PassCard 地址解析失败，但交易可能已提交
          String finalTxHash = txHash != null ? txHash : transactionHash;
          if (finalTxHash != null) {
            log.warn("链上PassCard发行交易已提交但地址解析失败: success={}, txHash={}", 
                success, finalTxHash);
            // 交易已提交，即使地址解析失败也记录交易hash
            requestMap.put("chainTxHash", finalTxHash);
          } else {
            log.error("链上PassCard发行失败: success={}, 未找到交易hash", success);
          }
        }
        // 写入一个NFT集合
        digitalAssetsColletion.setContractAddress(passCardAddress);
        digitalAssetsColletion.setChainEnv(chainEnv);

      } else {
        log.error("链上PassCard发行返回结果为空");
      }
    }

    digitalAssetsColletion.setMerchantNo(merchantNo);
    digitalAssetsColletion.setTenantId(loginUser.getTenantId());
  // contractProtocolCode 主题协议类型
  // 合约 metadata 文件夹
    digitalAssetsColletion.setCreateBy(loginUser.getBizRoleTypeNo());
    digitalAssetsColletion.setName((String) requestMap.get("name"));
    digitalAssetsColletion.setSymbol((String) requestMap.get("symbol"));

  // 6. digitalAssetsCollectionMapper 数据插入
    digitalAssetsCollectionMapper.insert(digitalAssetsColletion);

    return digitalAssetsColletion;
    // TODO: issue 抽离biz
    //digitalAssetsCollectionService.issue(requestMap);

  }

  /**
   * 品牌会员开卡:按照顾数字资产上架流程开卡 客户开卡，开卡即 mint 用户购买之后的回调
   * 实名信息或是DID领卡
   * 业务流程说明：
   *   1. 创建DID（去中心化身份标识）
   *   2、生成钱包 地址
   *   3. 为钱包地址铸造NFT（非同质化代币）作为会员卡
   *   4. 生成卡号：使用DID标识符 + NFT编号组合
   * @param requestMap
   * @return
   */
  @ShenyuDubboClient("/claim")
  @ApiDoc(desc = "claim")
  @Override
  public PassCardVo claim(Map<String, Object> requestMap) throws Exception {
    // ✅ 1. 参数校验
    LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
    String tenantId = loginUser.getTenantId();
    String customerNo = MapUtils.getString(requestMap, "customerNo");
    Boolean onChainFlag = MapUtils.getBoolean(requestMap, "onChainFlag");
    String digitalAssetsCollectionNo = MapUtils.getString(requestMap, "digitalAssetsCollectionNo");
    String digitalAssetsItemNo = MapUtils.getString(requestMap, "digitalAssetsItemNo");

    // 参数校验
    if (StringUtils.isBlank(customerNo)) {
      throw new BusinessException("WAAS_CUSTOMER_NO_REQUIRED", "客户编号不能为空");
    }
    if (StringUtils.isBlank(digitalAssetsCollectionNo)) {
      throw new BusinessException("WAAS_COLLECTION_NO_REQUIRED", "资产集合编号不能为空");
    }
    if (StringUtils.isBlank(digitalAssetsItemNo)) {
      throw new BusinessException("WAAS_ITEM_NO_REQUIRED", "数字资产项编号不能为空");
    }

    log.info("开始领卡流程: customerNo={}, digitalAssetsCollectionNo={}, digitalAssetsItemNo={}, onChainFlag={}", 
        customerNo, digitalAssetsCollectionNo, digitalAssetsItemNo, onChainFlag);

    // ✅ 2. 先查询资产卡片，确保存在后再进行后续操作
    DigitalAssetsCollection digitalAssetsCollection = digitalAssetsCollectionMapper.selectById(digitalAssetsCollectionNo);
    if (digitalAssetsCollection == null) {
      log.error("资产卡片不存在: digitalAssetsCollectionNo={}", digitalAssetsCollectionNo);
      throw new BusinessException("WAAS_ASSET_COLLECTION_NOT_FOUND", "资产卡片不存在");
    }
    log.info("查询到资产卡片: name={}, contractAddress={}, chainType={}, chainEnv={}, merchantNo={}",
        digitalAssetsCollection.getName(),
        digitalAssetsCollection.getContractAddress(),
        digitalAssetsCollection.getChainType(),
        digitalAssetsCollection.getChainEnv(),
        digitalAssetsCollection.getMerchantNo());

    // ✅ 3. 创建DID（去中心化身份标识）
    log.info("开始创建客户 DID: tenantId={}, customerNo={}", tenantId, customerNo);
    requestMap.put("tenantId", tenantId);
    requestMap.put("type", DidProfileType.INDIVIDUAL.getCode());
    DidProfile didProfile = didProfileServiceEngine.create(requestMap);
    log.info("客户 DID 创建成功: did={}, serialNo={}", didProfile.getDid(), didProfile.getSerialNo());

    String chainTokenId = "0";
    String chainTxHash = null;
    WalletAccount customerWalletAccountForChain = null;
    
    if(onChainFlag){
      log.info("链上铸造模式，开始准备链上资产铸造");
      requestMap.put("amount", "1");
      requestMap.put("limitClaim", "false");

      log.info("查询到资产卡片: name={}, contractAddress={}, chainType={}, chainEnv={}, merchantNo={}",
          digitalAssetsCollection.getName(),
          digitalAssetsCollection.getContractAddress(),
          digitalAssetsCollection.getChainType(),
          digitalAssetsCollection.getChainEnv(),
          digitalAssetsCollection.getMerchantNo());
      
      String chainIdentifier = digitalAssetsCollection.getChainType();
      // 2、生成钱包 地址
      // Wallet walletReq = new Wallet();
      //Wallet customerwallet = walletService.createMPCWallet(walletReq);
      // 根据链标识找出客户的链上地址
      log.info("查询客户钱包账户: chainIdentifier={}, customerNo={}", chainIdentifier, customerNo);
      WalletAccount customerWalletAccount = walletService.getWalletAccountByChainIdentifier(chainIdentifier, customerNo);
      if (customerWalletAccount == null) {
        log.error("客户钱包账户不存在: chainIdentifier={}, customerNo={}", chainIdentifier, customerNo);
        throw new BusinessException("WAAS_CUSTOMER_WALLET_ACCOUNT_MISSING", 
            "客户钱包账户不存在，无法接收PassCard");
      }
      log.info("查询到客户钱包账户: address={}", customerWalletAccount.getAddress());
      
      // 根据资产的归属，查询归属方的私钥
// 查询品牌的钱包账户，初始化钱包账户
      // 根据 MapUtils.getString(requestMap, "chainIdentifier") 获取链本币

      log.info("查询商户钱包账户: chainIdentifier={}, merchantNo={}", chainIdentifier, digitalAssetsCollection.getMerchantNo());
      WalletAccount merchantWalletAccount = walletService.getWalletAccountByChainIdentifier(chainIdentifier, digitalAssetsCollection.getMerchantNo());

      if (merchantWalletAccount == null) {
        log.error("商户钱包账户不存在: chainIdentifier={}, merchantNo={}", chainIdentifier, digitalAssetsCollection.getMerchantNo());
        throw new BusinessException("WAAS_WALLET_ACCOUNT_MISSING",
                "商户钱包账户不存在，无法发行PassCard");
      }
      log.info("查询到商户钱包账户: address={}", merchantWalletAccount.getAddress());

      // ✅ 4. 自动计算 tokenId
      String tokenId = calculateNextTokenId(digitalAssetsCollection);
      
      // ✅ 5. 构建铸造请求并执行链上铸造

      // 构建 tokenURI（可以从配置或 requestMap 获取，这里使用默认格式）
      String tokenURI = buildTokenURI(tokenId, requestMap);
      
      Map<String, Object> mintRequest = buildMintRequest(
          digitalAssetsCollection, 
          merchantWalletAccount, 
          customerWalletAccount, 
          tokenId, 
          tokenURI);
      
      log.info("准备链上铸造 PassCard: passCardAddress={}, recipient={}, tokenId={}, tokenURI={}",
          digitalAssetsCollection.getContractAddress(),
          customerWalletAccount.getAddress(),
          tokenId,
          tokenURI);
      
      // ✅ 执行链上铸造，失败时抛出异常
      Map<String, Object> mintResult = s11eProtocolService.mintPassCard(mintRequest);
      if (mintResult == null || !Boolean.TRUE.equals(mintResult.get("success"))) {
        String txHash = mintResult != null ? 
            (String) (mintResult.get("txHash") != null ? mintResult.get("txHash") : mintResult.get("transactionHash")) : null;
        log.error("链上 PassCard 铸造失败: tokenId={}, txHash={}, result={}", tokenId, txHash, mintResult);
        throw new BusinessException("WAAS_PASSCARD_MINT_FAILED", 
            "链上 PassCard 铸造失败，请检查链上交易状态: " + (txHash != null ? "txHash=" + txHash : ""));
      }
      
      String txHash = (String) (mintResult.get("txHash") != null ? mintResult.get("txHash") : mintResult.get("transactionHash"));
      log.info("链上 PassCard 铸造成功: tokenId={}, txHash={}", tokenId, txHash);
      
      // 保存链上铸造结果，供后续构建返回对象使用
      chainTokenId = tokenId;
      chainTxHash = txHash;
      customerWalletAccountForChain = customerWalletAccount;
//      digitalAssetsItemService.claim(requestMap);
//      customerProfileService.follow(requestMap);

    }

    // 查询出在售的数字资产
    DigitalAssetsItem digitalAssetsItemOnSale = digitalAssetsItemMapper.selectById(digitalAssetsItemNo);
    if (digitalAssetsItemOnSale == null) {
      log.error("在售数字资产不存在: digitalAssetsItemNo={}", digitalAssetsItemNo);
      throw new BusinessException("WAAS_ASSET_ITEM_NOT_FOUND", "在售数字资产不存在");
    }
    log.info("查询到在售数字资产: name={}, coverImage={}", 
        digitalAssetsItemOnSale.getAssetsName(), digitalAssetsItemOnSale.getCoverImage());

    // TODO 领卡的时候铸造出 digitalAssetsItem
    log.info("开始创建数字资产项");
    DigitalAssetsItem digitalAssetsItem = new DigitalAssetsItem();
    digitalAssetsItem.setTenantId(tenantId);
    String merchantNo = digitalAssetsCollection.getMerchantNo();
    digitalAssetsItem.setTokenId(new BigInteger(chainTokenId));
    digitalAssetsItem.setMerchantNo(merchantNo);
    digitalAssetsItem.setChainEnv(digitalAssetsCollection.getChainEnv());
    digitalAssetsItem.setChainType(digitalAssetsCollection.getChainType());
    digitalAssetsItem.setSerialNo(BsinSnowflake.getId());
    digitalAssetsItem.setDigitalAssetsCollectionNo(digitalAssetsCollectionNo);
    digitalAssetsItem.setAssetsType(digitalAssetsCollection.getAssetsType());
    digitalAssetsItem.setAssetsName(digitalAssetsCollection.getName());
    digitalAssetsItem.setCoverImage(digitalAssetsItemOnSale.getCoverImage());
    digitalAssetsItem.setQuantity(new BigDecimal(1));
    digitalAssetsItemMapper.insert(digitalAssetsItem);
    log.info("数字资产项创建成功: serialNo={}, assetsName={}, assetsType={}", 
        digitalAssetsItem.getSerialNo(), digitalAssetsItem.getAssetsName(), digitalAssetsItem.getAssetsType());

    // 11. 更新客户资产表
    log.info("更新客户资产表: customerNo={}, digitalAssetsItemNo={}, quantity=1", customerNo, digitalAssetsItem.getSerialNo());
    digitalAssetsItemBiz.updateCustomerDigitalAssets(
            digitalAssetsItem, customerNo, new BigDecimal(1), 1);
    log.info("客户资产表更新成功");
    
    //    1、数字徽章(ERC1155) 2、PFP(ERC71） 3、积分(ERC20) 4、门票(ERC1155)  5、pass卡(ERC1155)
    if (AssetsCollectionType.PASS_CARD.getCode().equals(digitalAssetsCollection.getAssetsType())) {
      log.info("资产类型为 PassCard，开始处理 PassCard 相关逻辑");
      // 12. 如果资产是 passCard 类型，
      // 12.1 插入到 customerPassCardMapper
      log.info("插入客户 PassCard 记录: customerNo={}, contractAddress={}, onChainFlag={}", 
          customerNo, digitalAssetsCollection.getContractAddress(), onChainFlag);
      digitalAssetsItemBiz.insertCustomerPassCard(onChainFlag,
              digitalAssetsItem, customerNo, digitalAssetsCollection.getContractAddress());
      log.info("客户 PassCard 记录插入成功");

      // 12.2 开通会员
      log.info("开始开通会员: customerNo={}, tenantId={}, merchantNo={}", 
          customerNo, tenantId, digitalAssetsItem.getMerchantNo());
      requestMap.put("customerNo", customerNo);
      requestMap.put("tenantId", tenantId);
      requestMap.put("merchantNo", digitalAssetsItem.getMerchantNo());
//      requestMap.put("nickname", customerBase.get("nickname"));
      memberService.openMember(requestMap);
      log.info("会员开通成功");
    }

    // ✅ 构建返回对象
    PassCardVo passCardVo = buildPassCardVo(
        didProfile, 
        digitalAssetsCollection, 
        digitalAssetsItem, 
        customerNo,
        customerWalletAccountForChain,
        chainTokenId,
        chainTxHash);
    
    log.info("PassCard 领卡完成: serialNo={}, did={}, tokenId={}, txHash={}, contractAddress={}", 
        passCardVo.getSerialNo(), 
        passCardVo.getDidProfile() != null ? passCardVo.getDidProfile().getDid() : null,
        passCardVo.getTokenId() != null ? passCardVo.getTokenId() : 
            (passCardVo.getDigitalAssetsItem() != null ? passCardVo.getDigitalAssetsItem().getTokenId() : null),
        passCardVo.getTxHash(),
        passCardVo.getContractAddress());
    
    return passCardVo;
  }

  @ShenyuDubboClient("/getPageList")
  @ApiDoc(desc = "getPageList")
  @Override
  public IPage<?> getPageList(Map<String, Object> requestMap) {
    LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
    Object paginationObj =  requestMap.get("pagination");
    Pagination pagination = new Pagination();
    BeanUtil.copyProperties(paginationObj,pagination);
    Page<Orderbook> page = new Page<>(pagination.getPageNum(),pagination.getPageSize());
    Page<CustomerPassCard> pageList = customerPassCardMapper.getPageList(page, loginUser.getTenantId(), loginUser.getMerchantNo());
    return pageList;
  }


  @ShenyuDubboClient("/getMemberList")
  @ApiDoc(desc = "getMemberList")
  @Override
  public List getMemberList(Map<String, Object> requestMap) {
    LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
    CustomerPassCard customerPassCardReq =
        BsinServiceContext.getReqBodyDto(CustomerPassCard.class, requestMap);
    LambdaQueryWrapper<CustomerPassCard> warapper = new LambdaQueryWrapper<>();
    warapper.eq(CustomerPassCard::getTenantId, loginUser.getTenantId());
    warapper.eq(CustomerPassCard::getMerchantNo, customerPassCardReq.getMerchantNo());
    List<CustomerPassCard> customerPassCardList = customerPassCardMapper.selectList(warapper);

    List<String> customerNos = new ArrayList<>();
    for (CustomerPassCard customerPassCard : customerPassCardList) {
      // 获取商户信息
      customerNos.add(customerPassCard.getCustomerNo());
    }
//    List<CustomerBase> customerList = new ArrayList<>();
//    if (customerNos.size() > 0) {
//      Map marketReqMap = new HashMap();
//      marketReqMap.put("customerNos", customerNos);
//      customerList = customerService.getListByCustomerNos(marketReqMap);
//    }
    return null;
  }

  /**
   * 查询商户发行的paas card
   * 发行之后上架的资产
   */
  @ShenyuDubboClient("/getMerchantPaasCardList")
  @ApiDoc(desc = "getMerchantPaasCardList")
  @Override
  public List<DigitalAssetsItemRes> getMerchantPaasCardList(Map<String, Object> requestMap) {
    LoginUser loginUser = LoginInfoContextHelper.getLoginUser();
    String merchantNo = MapUtils.getString(requestMap, "merchantNo");
    if(merchantNo == null){
      merchantNo = loginUser.getTenantMerchantNo();
    }
    List<String> assetsTypes = new ArrayList<>();
    assetsTypes.add(AssetsCollectionType.PASS_CARD.getCode());
    List<DigitalAssetsItemRes> digitalAssetsItemRes =
            digitalAssetsItemMapper.selectDigitalAssetsList(loginUser.getTenantId(), merchantNo , assetsTypes, "1");

    List<String> merchantNos = new ArrayList<>();
    for (DigitalAssetsItemRes digitalAssetsItem : digitalAssetsItemRes) {
      // 获取商户信息
      merchantNos.add(digitalAssetsItem.getMerchantNo());
    }
    if (merchantNos.size() > 0) {
      Map crmReqMap = new HashMap();
      crmReqMap.put("merchantNos", merchantNos);
//      List<Merchant> merchantList = merchantService.getListByMerchantNos(crmReqMap);
//      List<DigitalAssetsItem> digitalAssetsItemList = new ArrayList<>();
//      for (DigitalAssetsItem digitalAssetsItem : digitalAssetsItemPageList.getRecords()) {
//        // 找出商户信息
//        for (Merchant merchant : merchantList) {
//          if (digitalAssetsItem.getMerchantNo().equals(merchant.getSerialNo())) {
//            digitalAssetsItem.setMerchantName(merchant.getMerchantName());
//            digitalAssetsItem.setMerchantLogo(merchant.getLogoUrl());
//          }
//        }
//        digitalAssetsItemList.add(digitalAssetsItem);
//      }
//      digitalAssetsItemListRes.setRecords(digitalAssetsItemList);
    }
    return digitalAssetsItemRes;
  }

  /**
   * 查询客户在商户下的pass卡
   *
   * @param requestMap
   * @return
   */
  @ShenyuDubboClient("/getCustomerPaasCardByMerchantNo")
  @ApiDoc(desc = "getCustomerPaasCardByMerchantNo")
  @Override
  public DigitalAssetsDetailRes getCustomerPaasCardByMerchantNo(Map<String, Object> requestMap) {
    String tenantId = LoginInfoContextHelper.getTenantId();
    String customerNo = LoginInfoContextHelper.getCustomerNo();
    String merchantNo = MapUtils.getString(requestMap, "merchantNo");
    DigitalAssetsItemRes digitalAssetsItemRes =
        customerPassCardMapper.selectCustomerDigitalAssetsDetail(tenantId, merchantNo, customerNo);

    DigitalAssetsDetailRes digitalAssetsDetailRes = null;
    if (digitalAssetsItemRes != null) {
      digitalAssetsDetailRes =
          digitalAssetsItemBiz.getDetail(
              digitalAssetsItemRes.getDigitalAssetsCollectionNo(),
              digitalAssetsItemRes.getSerialNo(),
              digitalAssetsItemRes.getTokenId());
      digitalAssetsItemRes.setMerchantLogo(digitalAssetsDetailRes.getDigitalAssetsItem().getMerchantLogo());
      digitalAssetsItemRes.setMerchantName(digitalAssetsDetailRes.getDigitalAssetsItem().getMerchantName());
      digitalAssetsDetailRes.setCustomerPassCard(digitalAssetsItemRes);
    }
    // TODO 成交记录数据
    return digitalAssetsDetailRes;
  }

  /**
   * 构建 PassCardVo 返回对象
   * @param didProfile DID 信息
   * @param digitalAssetsCollection 资产集合
   * @param digitalAssetsItem 数字资产项
   * @param customerNo 客户编号
   * @param customerWalletAccount 客户钱包账户（链上铸造时才有）
   * @param tokenId tokenId（链上铸造时才有）
   * @param txHash 交易哈希（链上铸造时才有）
   * @return PassCardVo 对象
   */
  private PassCardVo buildPassCardVo(
      DidProfile didProfile,
      DigitalAssetsCollection digitalAssetsCollection,
      DigitalAssetsItem digitalAssetsItem,
      String customerNo,
      WalletAccount customerWalletAccount,
      String tokenId,
      String txHash) {
    PassCardVo passCardVo = new PassCardVo();
    
    // ✅ 1. 填充 DigitalAssetsCollection 的字段（继承字段）
    BeanUtil.copyProperties(digitalAssetsCollection, passCardVo);
    
    // ✅ 2. 设置 DID 信息
    passCardVo.setDidProfile(didProfile);
    
    // ✅ 3. 设置数字资产项信息
    if (digitalAssetsItem != null) {
      // 如果链上铸造，设置 tokenId
      if (StringUtils.isNotBlank(tokenId)) {
        try {
          BigInteger tokenIdBigInt = new BigInteger(tokenId);
          digitalAssetsItem.setTokenId(tokenIdBigInt);
          // 同时在顶层也设置 tokenId，方便访问
          passCardVo.setTokenId(tokenIdBigInt);
          log.debug("设置 tokenId: {}", tokenIdBigInt);
        } catch (NumberFormatException e) {
          log.warn("无法将 tokenId 转换为 BigInteger: {}", tokenId);
        }
      }
      passCardVo.setDigitalAssetsItem(digitalAssetsItem);
    }
    
    // ✅ 4. 设置链上交易哈希（如果链上铸造）
    if (StringUtils.isNotBlank(txHash)) {
      passCardVo.setTxHash(txHash);
      log.debug("设置 txHash: {}", txHash);
    }
    
    // ✅ 5. 设置钱包信息（如果有客户钱包账户）
    if (customerWalletAccount != null && StringUtils.isNotBlank(customerWalletAccount.getWalletNo())) {
      try {
        Wallet wallet = walletMapper.selectById(customerWalletAccount.getWalletNo());
        if (wallet != null) {
          passCardVo.setWallet(wallet);
          log.debug("查询到客户钱包: walletNo={}, walletName={}", wallet.getSerialNo(), wallet.getWalletName());
        } else {
          log.warn("未找到客户钱包: walletNo={}", customerWalletAccount.getWalletNo());
        }
      } catch (Exception e) {
        log.warn("查询客户钱包失败: walletNo={}, error={}", customerWalletAccount.getWalletNo(), e.getMessage());
      }
    }
    
    return passCardVo;
  }

  /**
   * 检查地址是否为零地址
   * @param address 地址字符串
   * @return true 如果是零地址，false 否则
   */
  private boolean isZeroAddress(String address) {
    if (StringUtils.isBlank(address)) {
      return true;
    }
    // 检查是否为以太坊零地址（不区分大小写）
    String normalizedAddress = address.toLowerCase().trim();
    return normalizedAddress.equals("0x0000000000000000000000000000000000000000") ||
           normalizedAddress.equals("0x0") ||
           normalizedAddress.equals("0");
  }

  /**
   * 自动计算下一个 tokenId
   * @param digitalAssetsCollection 资产集合
   * @return 下一个 tokenId
   */
  private String calculateNextTokenId(DigitalAssetsCollection digitalAssetsCollection) {
    log.info("开始自动计算 tokenId，查询链上总供应量: passCardAddress={}, chainIdentifier={}, chainEnv={}",
        digitalAssetsCollection.getContractAddress(),
        digitalAssetsCollection.getChainType(),
        digitalAssetsCollection.getChainEnv());
    
    try {
      Map<String, Object> totalSupplyRequest = new HashMap<>();
      totalSupplyRequest.put("chainIdentifier", digitalAssetsCollection.getChainType());
      totalSupplyRequest.put("chainEnv", digitalAssetsCollection.getChainEnv());
      totalSupplyRequest.put("passCardAddress", digitalAssetsCollection.getContractAddress());

      Map<String, Object> totalSupplyResult = s11eProtocolService.getPassCardTotalSupply(totalSupplyRequest);
      log.debug("链上查询 totalSupply 返回结果: {}", totalSupplyResult);

      if (totalSupplyResult == null || !Boolean.TRUE.equals(totalSupplyResult.get("success"))) {
        throw new RuntimeException("链上查询 totalSupply 失败");
      }

      Object totalSupplyObj = totalSupplyResult.get("totalSupply");
      if (totalSupplyObj == null) {
        throw new RuntimeException("链上查询 totalSupply 返回值为空");
      }

      BigInteger totalSupply = convertToBigInteger(totalSupplyObj);
      if (totalSupply == null) {
        throw new RuntimeException("无法解析链上 totalSupply 返回值类型: " + totalSupplyObj.getClass().getName());
      }

      // 下一个 tokenId = totalSupply + 1（tokenId 必须 > 0）
      BigInteger nextTokenId = totalSupply.add(BigInteger.ONE);
      // 确保 tokenId >= 1
      if (nextTokenId.compareTo(BigInteger.ONE) < 0) {
        nextTokenId = BigInteger.ONE;
      }
      String tokenId = nextTokenId.toString();
      log.info("自动计算下一个 tokenId: totalSupply={}, nextTokenId={}", totalSupply, tokenId);
      return tokenId;
    } catch (Exception e) {
      log.error("查询链上 totalSupply 失败: {}", e.getMessage(), e);
      throw new BusinessException("WAAS_TOKEN_ID_AUTO_CALC_FAILED",
          "无法自动计算 tokenId，请手动提供 tokenId 参数: " + e.getMessage());
    }
  }

  /**
   * 将对象转换为 BigInteger
   * @param obj 待转换对象
   * @return BigInteger 对象，如果无法转换则返回 null
   */
  private BigInteger convertToBigInteger(Object obj) {
    if (obj == null) {
      return null;
    }
    if (obj instanceof BigInteger) {
      return (BigInteger) obj;
    }
    if (obj instanceof String) {
      try {
        return new BigInteger((String) obj);
      } catch (NumberFormatException e) {
        log.warn("无法将字符串转换为 BigInteger: {}", obj);
        return null;
      }
    }
    if (obj instanceof Number) {
      return BigInteger.valueOf(((Number) obj).longValue());
    }
    return null;
  }

  /**
   * 构建 tokenURI
   * @param tokenId tokenId
   * @param requestMap 请求参数
   * @return tokenURI
   */
  private String buildTokenURI(String tokenId, Map<String, Object> requestMap) {
    // 优先从 requestMap 获取，如果没有则使用默认格式
    String tokenURI = MapUtils.getString(requestMap, "tokenURI");
    if (StringUtils.isBlank(tokenURI)) {
      // 可以从配置获取 baseURI，这里使用默认格式
      String baseURI = s11eConfig != null && s11eConfig.getBaseUri() != null 
          ? s11eConfig.getBaseUri() 
          : "ipfs://QmJavaTest/";
      tokenURI = baseURI + tokenId + ".json";
    }
    return tokenURI;
  }

  /**
   * 构建铸造请求
   * @param digitalAssetsCollection 资产集合
   * @param merchantWalletAccount 商户钱包账户
   * @param customerWalletAccount 客户钱包账户
   * @param tokenId tokenId
   * @param tokenURI tokenURI
   * @return 铸造请求 Map
   */
  private Map<String, Object> buildMintRequest(
      DigitalAssetsCollection digitalAssetsCollection,
      WalletAccount merchantWalletAccount,
      WalletAccount customerWalletAccount,
      String tokenId,
      String tokenURI) {
    Map<String, Object> request = new HashMap<>();
    request.put("chainIdentifier", digitalAssetsCollection.getChainType());
    request.put("chainEnv", digitalAssetsCollection.getChainEnv());
    request.put("privateKey", merchantWalletAccount.getPrivateKey());
    request.put("passCardAddress", digitalAssetsCollection.getContractAddress());
    request.put("to", customerWalletAccount.getAddress());
    request.put("tokenId", tokenId);
    request.put("tokenURI", tokenURI);
    return request;
  }

}
